package com.greyshark.bledemo.ui

import android.R
import android.bluetooth.BluetoothDevice
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Handler
import android.view.View
import android.widget.CalendarView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.dialog.suotalib.global.SuotaLibConfig
import com.dialog.suotalib.global.SuotaProfile
import com.dialog.suotalib.interfaces.callbacks.ISuotaManagerCallback
import com.dialog.suotalib.suota.SuotaFile
import com.dialog.suotalib.suota.SuotaManager
import com.dialog.suotalib.suota.SuotaManagerCallback
import com.google.gson.Gson
import com.greyshark.bledemo.base.BaseActivity
import com.greyshark.bledemo.base.SimpleAdapter
import com.greyshark.bledemo.databinding.ActivityFunctionBinding
import com.greyshark.bledemo.databinding.LayoutItemFunctionBinding
import com.greyshark.bledemo.databinding.LayoutItemPacketBinding
import com.greyshark.bledemo.entity.TitlePacketEntity
import com.greyshark.lib.bluetooth.BleConnectEvent
import com.greyshark.lib.bluetooth.ControlCenterClient
import com.greyshark.lib.bluetooth.ProtocolCommand
import com.greyshark.lib.bluetooth.callback.CommonResultInfoCallback
import com.greyshark.lib.bluetooth.callback.DataPacketCallback
import com.greyshark.lib.bluetooth.callback.query.BatteryInfoCallback
import com.greyshark.lib.bluetooth.callback.query.BloodOxygenCallback
import com.greyshark.lib.bluetooth.callback.query.DailyInfoCallback
import com.greyshark.lib.bluetooth.callback.query.DaySleepCallback
import com.greyshark.lib.bluetooth.callback.query.DeviceInfoCallback
import com.greyshark.lib.bluetooth.callback.query.EffectiveStandCallback
import com.greyshark.lib.bluetooth.callback.query.HealthInfoCallback
import com.greyshark.lib.bluetooth.callback.query.HeartRateCallback
import com.greyshark.lib.bluetooth.callback.query.LightingInfoCallback
import com.greyshark.lib.bluetooth.callback.query.NightSleepCallback
import com.greyshark.lib.bluetooth.callback.query.RealTimeSportCallback
import com.greyshark.lib.bluetooth.callback.query.SportRecordCallback
import com.greyshark.lib.bluetooth.callback.query.SupportFunctionCallback
import com.greyshark.lib.bluetooth.callback.query.TemperatureCallback
import com.greyshark.lib.bluetooth.callback.query.UserInfoCallback
import com.greyshark.lib.bluetooth.core.CallbackManager
import com.greyshark.lib.bluetooth.entity.query.DailyDataEntity
import com.greyshark.lib.bluetooth.entity.query.DaySleepEntity
import com.greyshark.lib.bluetooth.entity.query.DeviceInfoEntity
import com.greyshark.lib.bluetooth.entity.query.EffectiveStandEntity
import com.greyshark.lib.bluetooth.entity.query.HealthInfoEntity
import com.greyshark.lib.bluetooth.entity.query.LightingInfoEntity
import com.greyshark.lib.bluetooth.entity.query.NightSleepEntity
import com.greyshark.lib.bluetooth.entity.query.SportRecordInfoEntity
import com.greyshark.lib.bluetooth.entity.query.SupportFunctionEntity
import com.greyshark.lib.bluetooth.entity.query.UserInfoEntity
import com.greyshark.lib.bluetooth.utils.BleLogger
import com.greyshark.lib.bluetooth.utils.ByteHexUtils
import com.greyshark.lib.bluetooth.utils.LogUtils
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale

class FunctionActivity : BaseActivity<ActivityFunctionBinding>(
  inflate = ActivityFunctionBinding::inflate
), View.OnClickListener {

  private val tag = FunctionActivity::class.java.simpleName

  private val functionList = arrayListOf<TitlePacketEntity>()
  private val packetList = arrayListOf<TitlePacketEntity>()

  private var deviceName: String = ""
  private var deviceAddress: String = ""

  private var device: BluetoothDevice? = null

  private var selectTimestampMillis:Long = System.currentTimeMillis()

  override fun onClick(v: View?) {
    when (v?.id) {
      binding.layoutDevice.id -> {
      }
      binding.tvSelectCalendar.id -> {
        binding.calendarView.visibility = View.VISIBLE
      }

      else -> {}
    }
  }

  override fun initUI() {
    super.initUI()
    binding.rvFunction.apply {
      layoutManager = LinearLayoutManager(this@FunctionActivity)
      adapter = functionAdapter
    }

    binding.rvPacket.apply {
      layoutManager = LinearLayoutManager(this@FunctionActivity)
      adapter = packetAdapter
    }
  }


  override fun initData() {
    super.initData()
    binding.calendarView.invalidate()
    setViewsClickListener(this, binding.layoutDevice)
    setViewsClickListener(this, binding.tvSelectCalendar)

    val currentCalendar = Calendar.getInstance()
    binding.calendarView.init(currentCalendar.get(Calendar.YEAR), currentCalendar.get(Calendar.MONTH), currentCalendar.get(Calendar.DAY_OF_MONTH)) { view, year, monthOfYear, dayOfMonth ->
      val selectedDate = "$year-${monthOfYear + 1}-$dayOfMonth"
      binding.tvSelectCalendar.text = selectedDate
      binding.calendarView.visibility = View.GONE
      // 获取选中日期的时间戳
      val selectedCalendar = Calendar.getInstance().apply {
        set(Calendar.YEAR, year)
        set(Calendar.MONTH, monthOfYear)
        set(Calendar.DAY_OF_MONTH, dayOfMonth)
        set(Calendar.HOUR_OF_DAY, 23)  // 设置为当天的23:59:59
        set(Calendar.MINUTE, 59)
        set(Calendar.SECOND, 59)
        set(Calendar.MILLISECOND, 999)
      }
      selectTimestampMillis = selectedCalendar.timeInMillis  // 毫秒级时间戳
    }

      lifecycleScope.launch {
      ControlCenterClient.instance.connectStateFlowable()
        .onEach { it ->
          BleLogger.i(tag, "connect event is ${it.javaClass.simpleName}")
          when (it) {
            is BleConnectEvent.ConnectDeviceGattErrorEvent -> {}
            is BleConnectEvent.ConnectDeviceNotFoundEvent -> {}
            is BleConnectEvent.ConnectDiscoverServiceTimeOutEvent -> {}
            is BleConnectEvent.ConnectParamIllegalEvent -> {}
            is BleConnectEvent.ConnectUnknowErrorEvent -> {}
            is BleConnectEvent.PermissionDeniedEvent -> {}
            is BleConnectEvent.ConnectTimeOutEvent -> {}
            is BleConnectEvent.DisConnectingEvent -> {}
            is BleConnectEvent.DisConnectedEvent -> {
              binding.tvStatus.text = "已断开"
            }

            is BleConnectEvent.ConnectingEvent -> {
              binding.tvStatus.text = "连接中ing"
            }

            is BleConnectEvent.ConnectedEvent -> {
              binding.tvStatus.text = "已连接"
            }

            else -> {
              binding.tvStatus.text = "未知状态"
            }
          }
        }
        .collect()
    }

    device = intent.getParcelableExtra("BLE_DEVICE")!!
    deviceName = intent.getStringExtra("BLE_NAME").toString()
    deviceAddress = intent.getStringExtra("BLE_ADDRESS").toString()
    LogUtils.i(tag, "deviceName=$deviceName; deviceAddress=$deviceAddress")

    binding.tvName.text = deviceName
    binding.tvMac.text = deviceAddress
    binding.tvStatus.visibility = View.VISIBLE
    binding.tvStatus.text = "未连接"

    Handler(mainLooper).postDelayed({
      ControlCenterClient.instance.connect(deviceName, deviceAddress)
    }, 1000)


    functionList.apply {
      add(TitlePacketEntity(title = "查询设备信息", packet = ProtocolCommand.queryDeviceInfo()))
      add(TitlePacketEntity(title = "查询电量信息", packet = ProtocolCommand.queryDeviceBattery()))
      add(TitlePacketEntity(title = "查询⽤户信息", packet = ProtocolCommand.queryUserInfo()))
      add(
        TitlePacketEntity(
          title = "查询健康信息",
          packet = ProtocolCommand.queryHealthInfo(selectTimestampMillis / 1000)
        )
      )
      add(
        TitlePacketEntity(
          title = "查询睡眠信息",
          packet = ProtocolCommand.queryNightTimeSleepInfo(selectTimestampMillis / 1000)
        )
      )
      add(
        TitlePacketEntity(
          title = "查询⼩睡信息",
          packet = ProtocolCommand.queryDayTimeSleepInfo(selectTimestampMillis / 1000)
        )
      )
      add(
        TitlePacketEntity(
          title = "查询运动记录",
          packet = ProtocolCommand.querySportRecordInfo(selectTimestampMillis / 1000)
        )
      )
      add(
        TitlePacketEntity(
          title = "开关实时运动上报",
          packet = ProtocolCommand.queryRealTimeSportInfo(true)
        )
      )
      add(
        TitlePacketEntity(
          title = "查询有效站⽴",
          packet = ProtocolCommand.queryEffectStandInfo(selectTimestampMillis / 1000)
        )
      )
      add(
        TitlePacketEntity(
          title = "开关实时⼼率上报",
          packet = ProtocolCommand.queryHeartRateInfo(true)
        )
      )
      add(
        TitlePacketEntity(
          title = "开关实时⾎氧上报",
          packet = ProtocolCommand.queryBloodOxygenInfo(true)
        )
      )
      add(
        TitlePacketEntity(
          title = "开关实时体温上报",
          packet = ProtocolCommand.queryTemperatureInfo(true)
        )
      )
      add(TitlePacketEntity(title = "查询⽀持功能", packet = ProtocolCommand.querySupportFunction()))
      add(
        TitlePacketEntity(
          title = "查询⽇常数据",
          packet = ProtocolCommand.queryDailyInfo(selectTimestampMillis / 1000)
        )
      )

      add(
        TitlePacketEntity(
          title = "查询灯光数据",
          packet = ProtocolCommand.queryDailyInfo(selectTimestampMillis / 1000)
        )
      )

      add(
        TitlePacketEntity(
          title = "同步时间",
          packet = ProtocolCommand.pushTimeInfo(System.currentTimeMillis() / 1000, 8 + 12)
        )
      )
      add(
        TitlePacketEntity(
          title = "同步灯光控制",
          packet = ProtocolCommand.syncLightingInfo(
            LightingInfoEntity(
              index = 0,
              switch = true,
              mode = 1,
              rgb = 0x9876aa,
              brightness = 2,
              speed = 2,
              duration = 5,
              interval = 3
            )
          )
        )
      )
      add(TitlePacketEntity(title = "重启", packet = ProtocolCommand.reboot()))
      add(TitlePacketEntity(title = "恢复出⼚", packet = ProtocolCommand.factoryReset()))
      add(
        TitlePacketEntity(
          title = "同步⽤户信息",
          packet = ProtocolCommand.pushUserInfo(100, 170, true, selectTimestampMillis / 1000)
        )
      )
      add(
        TitlePacketEntity(
          title = "同步运动信息",
          packet = ProtocolCommand.pushSportInfo(1, 1, selectTimestampMillis / 1000)
        )
      )
      add(TitlePacketEntity(title = "同步界⾯", packet = ProtocolCommand.pushAppRunningStatus(true)))
      add(TitlePacketEntity(title = "OTA", packet = ProtocolCommand.pushAppRunningStatus(true)))

    }
    binding.rvFunction.adapter?.notifyDataSetChanged()

    packetList.apply {
      add(
        TitlePacketEntity(
          isApp = true,
          title = "App发(测试数据)",
          packet = byteArrayOf(
            0x00.toByte(), 0x11.toByte(), 0x22.toByte(), 0x33.toByte(),
            0x44.toByte(), 0x55.toByte(), 0x66.toByte(), 0x77.toByte(),
            0x88.toByte(), 0x99.toByte(), 0xaa.toByte(), 0xbb.toByte(),
            0xcc.toByte(), 0xdd.toByte(), 0xee.toByte(), 0xff.toByte()
          )
        )
      )
    }
    binding.rvPacket.adapter?.notifyDataSetChanged()

    CallbackManager.dataPacketCallback = object : DataPacketCallback {

      override fun onResult(time: Long, packet: ByteArray) {
        val entity = TitlePacketEntity(
          isApp = false,
          title = "设备回",
          packet = packet,
          time = time
        )
        packetList.add(entity)
        runOnUiThread {
          binding.rvPacket.adapter?.notifyDataSetChanged()
        }
      }
    }
  }

  private val gson = Gson()
  private val functionAdapter =
    object : SimpleAdapter<TitlePacketEntity, LayoutItemFunctionBinding>(
      data = functionList,
      inflater = LayoutItemFunctionBinding::inflate,
    ) {
      override fun onBindData(
        binding: LayoutItemFunctionBinding?,
        t: TitlePacketEntity,
        position: Int
      ) {
        binding?.apply {
          btFunction.text = t.title
          btFunction.setOnClickListener {
            packetList.add(
              TitlePacketEntity(
                isApp = true,
                title = "App发",
                packet = t.packet,
                time = System.currentTimeMillis()
              )
            )

            when (t.title) {
              //todo 用于多指令测试，后删
              "同步界⾯" -> {
                ControlCenterClient.instance.queryDeviceInfo(null)
                ControlCenterClient.instance.queryBatteryInfo(null)
                ControlCenterClient.instance.queryUserInfo(null)
                ControlCenterClient.instance.queryLightingInfo(null)
                ControlCenterClient.instance.queryNightSleepInfo(
                  selectTimestampMillis / 1000,
                  null
                )
                ControlCenterClient.instance.queryDaySleepInfo(
                  selectTimestampMillis / 1000,
                  null
                )
                ControlCenterClient.instance.queryHealthInfo(
                  selectTimestampMillis / 1000,
                  null
                )
                ControlCenterClient.instance.queryDailyInfo(
                  selectTimestampMillis / 1000,
                  null
                )
                ControlCenterClient.instance.queryEffectiveStandInfo(
                  selectTimestampMillis / 1000,
                  null
                )
                ControlCenterClient.instance.querySportRecordInfo(
                  selectTimestampMillis / 1000,
                  null
                )
              }

              "OTA" -> {
                // 启动文件选择器
                val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
                  type = "*/*" // 允许选择所有类型文件
                  addCategory(Intent.CATEGORY_OPENABLE)
                }
                filePickerLauncher.launch(intent)
              }

              "查询设备信息" -> {
                ControlCenterClient.instance.queryDeviceInfo(object : DeviceInfoCallback {
                  override fun onTimeout() {
                    LogUtils.i(tag, "queryDeviceInfo onTimeout")
                  }

                  override fun onError(message: String) {
                    LogUtils.i(tag, "queryDeviceInfo onError")
                  }

                  override fun onData(info: DeviceInfoEntity) {
                    val json = gson.toJson(info)
                    LogUtils.i(tag, "queryDeviceInfo json=${json}")
                    packetList.add(
                      TitlePacketEntity(
                        json = json
                      )
                    )
                  }
                })
              }

              "查询电量信息" -> {
                ControlCenterClient.instance.queryBatteryInfo(object : BatteryInfoCallback {
                  override fun onTimeout() {}

                  override fun onError(message: String) {}

                  override fun onData(battery: Int, isCharge: Boolean) {
                    LogUtils.i(tag, "queryBatteryInfo battery=${battery}, isCharge=$isCharge")
                    packetList.add(
                      TitlePacketEntity(
                        json = "battery=${battery}, isCharge=$isCharge"
                      )
                    )
                  }

                })
              }

              "查询⽤户信息" -> {
                ControlCenterClient.instance.queryUserInfo(object : UserInfoCallback {
                  override fun onTimeout() {}

                  override fun onError(message: String) {}

                  override fun onData(info: UserInfoEntity) {
                    val json = gson.toJson(info)
                    LogUtils.i(tag, "queryUserInfo json=${json}")
                    packetList.add(
                      TitlePacketEntity(
                        json = json
                      )
                    )
                  }

                })
              }
              //todo 后面传时间皆需传秒级时间戳
              "查询健康信息" -> {
                ControlCenterClient.instance.queryHealthInfo(
                  selectTimestampMillis / 1000,
                  object : HealthInfoCallback {
                    override fun onTimeout() {}

                    override fun onError(message: String) {}

                    override fun onData(info: MutableList<HealthInfoEntity>) {
                      val json = gson.toJson(info)
                      LogUtils.i(tag, "queryHealthInfo json=${json}")
                      packetList.add(
                        TitlePacketEntity(
                          json = json
                        )
                      )
                    }

                  })
              }

              "查询⽇常数据" -> {
                ControlCenterClient.instance.queryDailyInfo(
                  selectTimestampMillis / 1000,
                  object : DailyInfoCallback {
                    override fun onTimeout() {}

                    override fun onError(message: String) {}

                    override fun onData(info: MutableList<DailyDataEntity>) {
                      val json = gson.toJson(info)
                      LogUtils.i(tag, "queryDailyInfo json=${json}")
                      packetList.add(
                        TitlePacketEntity(
                          json = json
                        )
                      )
                    }

                  })
              }

              "查询灯光数据" -> {
                ControlCenterClient.instance.queryLightingInfo(object : LightingInfoCallback {
                  override fun onTimeout() {}

                  override fun onError(message: String) {}

                  override fun onData(queue: MutableList<LightingInfoEntity>) {
                    LogUtils.i(tag, "queryLightingInfo json=${gson.toJson(queue)}")
                  }

                })
              }

              "同步灯光控制" -> {
                ControlCenterClient.instance.syncLighting(LightingInfoEntity(
                  index = 0,
                  switch = true,
                  mode = 3,
                  rgb = 0xff0000,
                  brightness = 11,
                  speed = 9,
                  duration = 30,
                  interval = 255
                ),object : CommonResultInfoCallback {
                  override fun onTimeout() {}

                  override fun onError(message: String) {}
                  override fun onData(code: Int) {
                    LogUtils.i(tag, "syncLighting code=$code")
                  }
                })
              }

              "查询睡眠信息" -> {
                ControlCenterClient.instance.queryNightSleepInfo(
                  selectTimestampMillis / 1000,
                  object : NightSleepCallback {
                    override fun onTimeout() {}

                    override fun onError(message: String) {}

                    override fun onData(info: MutableList<NightSleepEntity>) {
                      val json = gson.toJson(info)
                      LogUtils.i(tag, "queryNightSleepInfo json=${json}")
                      packetList.add(
                        TitlePacketEntity(
                          json = json
                        )
                      )
                    }

                  })

                ControlCenterClient.instance.queryLightingInfo(object : LightingInfoCallback {
                  override fun onTimeout() {}

                  override fun onError(message: String) {}

                  override fun onData(queue: MutableList<LightingInfoEntity>) {
                    LogUtils.i(tag, "queryLightingInfo json=${gson.toJson(queue)}")
                  }

                })

                ControlCenterClient.instance.queryDailyInfo(
                  selectTimestampMillis / 1000,
                  object : DailyInfoCallback {
                    override fun onTimeout() {}

                    override fun onError(message: String) {}

                    override fun onData(info: MutableList<DailyDataEntity>) {
                      val json = gson.toJson(info)
                      LogUtils.i(tag, "queryDailyInfo json=${json}")
                      packetList.add(
                        TitlePacketEntity(
                          json = json
                        )
                      )
                    }

                  })
              }

              "查询⼩睡信息" -> {
                ControlCenterClient.instance.queryDaySleepInfo(
                  selectTimestampMillis / 1000,
                  object : DaySleepCallback {
                    override fun onTimeout() {}

                    override fun onError(message: String) {}

                    override fun onData(info: MutableList<DaySleepEntity>) {
                      val json = gson.toJson(info)
                      LogUtils.i(tag, "queryDaySleepInfo json=${json}")
                      packetList.add(
                        TitlePacketEntity(
                          json = json
                        )
                      )
                    }

                  })
              }

              "查询有效站⽴" -> {
                ControlCenterClient.instance.queryEffectiveStandInfo(
                  selectTimestampMillis / 1000,
                  object : EffectiveStandCallback {
                    override fun onTimeout() {}

                    override fun onError(message: String) {}

                    override fun onData(info: MutableList<EffectiveStandEntity>) {
                      val json = gson.toJson(info)
                      LogUtils.i(tag, "queryEffectiveStandInfo json=${json}")
                      packetList.add(
                        TitlePacketEntity(
                          json = json
                        )
                      )
                    }

                  })
              }

              "查询运动记录" -> {
                ControlCenterClient.instance.querySportRecordInfo(
                  selectTimestampMillis / 1000,
                  object : SportRecordCallback {
                    override fun onTimeout() {}

                    override fun onError(message: String) {}

                    override fun onData(info: MutableList<SportRecordInfoEntity>) {
                      val json = gson.toJson(info)
                      LogUtils.i(tag, "querySportRecordInfo json=${json}")
                      packetList.add(
                        TitlePacketEntity(
                          json = json
                        )
                      )
                    }

                  })
              }

              "查询⽀持功能" -> {
                ControlCenterClient.instance.querySupportFunction(object : SupportFunctionCallback {
                  override fun onTimeout() {}

                  override fun onError(message: String) {}

                  override fun onData(entity: SupportFunctionEntity) {
                    val json = gson.toJson(entity)
                    LogUtils.i(tag, "querySupportFunction json=${json}")
                    packetList.add(
                      TitlePacketEntity(
                        json = json
                      )
                    )
                  }

                })
              }

              //todo status = 1:开启成功；2:关闭成功； 3:开启失败，当前已打开实时查询；4:关闭失败，当前没有实时查询
              "开关实时运动上报" -> {
                ControlCenterClient.instance.openRealTimeSportReport(
                  true,
                  object : RealTimeSportCallback {
                    override fun onTimeout() {}

                    override fun onError(message: String) {}

                    override fun onData(status: Int) {}

                  })
              }

              "开关实时⼼率上报" -> {
                ControlCenterClient.instance.openHeartRateReport(true, object : HeartRateCallback {
                  override fun onTimeout() {}

                  override fun onError(message: String) {}

                  override fun onData(status: Int) {}

                })
              }

              "开关实时⾎氧上报" -> {
                ControlCenterClient.instance.openBloodOxygenReport(
                  true,
                  object : BloodOxygenCallback {
                    override fun onTimeout() {}

                    override fun onError(message: String) {}

                    override fun onData(status: Int) {}

                  })
              }

              "开关实时体温上报" -> {
                ControlCenterClient.instance.openTemperatureReport(
                  true,
                  object : TemperatureCallback {
                    override fun onTimeout() {}

                    override fun onError(message: String) {}

                    override fun onData(status: Int) {}

                  })
              }

              else -> {
                ControlCenterClient.instance.sendCommand(t.packet)
              }
            }
          }
        }
      }

    }

  private val filePickerLauncher =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
      if (result.resultCode == RESULT_OK) {
        result.data?.data?.let { uri: Uri ->
          // 使用 uri 进行后续操作
          LogUtils.i(tag, "Selected file Uri: $uri")
          startOTA(uri)
        }
      }
    }

  val MISO_GPIO_INDEX: Int = 0
  val MOSI_GPIO_INDEX: Int = 1
  val CS_GPIO_INDEX: Int = 2
  val SCK_GPIO_INDEX: Int = 3
  val SCL_GPIO_INDEX: Int = 4
  val SDA_GPIO_INDEX: Int = 5

  private val gpioValues = listOf(
    SuotaLibConfig.Default.MISO_GPIO,
    SuotaLibConfig.Default.MOSI_GPIO,
    SuotaLibConfig.Default.CS_GPIO,
    SuotaLibConfig.Default.SCK_GPIO,
    SuotaLibConfig.Default.SCL_GPIO,
    SuotaLibConfig.Default.SDA_GPIO
  )

  private fun startOTA(uri: Uri) {
    val otaManager = SuotaManager(
      lifecycle,
      this@FunctionActivity,
      device,
//      MySuotaCallback()
      object : SuotaManagerCallback() {
        override fun onSuccess(totalElapsedSeconds: Double, imageUploadElapsedSeconds: Double) {
          LogUtils.i(tag, "OTA onSuccess")
        }

        override fun onFailure(errorCode: Int) {
          LogUtils.i(tag, "OTA onFailure")
        }

        override fun onUploadProgress(percent: Float) {
          LogUtils.i(tag, "OTA progress = $percent")
        }

        override fun onDeviceReady() {
          LogUtils.i(tag, "OTA start")
        }

        override fun onSuotaLog(
          state: SuotaProfile.SuotaProtocolState?,
          type: ISuotaManagerCallback.SuotaLogType?,
          log: String?
        ) {
          LogUtils.i(tag, "OTA log = $log")
        }

        override fun onBlockSent(block: Int, totalBlocks: Int) {
          LogUtils.i(tag, "OTA block = $block, totalBlocks = $totalBlocks")
        }
      }
    )
    otaManager.apply {
      setUiContext(this@FunctionActivity)
      setSuotaFile(SuotaFile(this@FunctionActivity, uri))
//      startAsymmetricSuota()
      initializeSuota(
        240,
        gpioValues[MISO_GPIO_INDEX],
        gpioValues[MOSI_GPIO_INDEX],
        gpioValues[CS_GPIO_INDEX],
        gpioValues[SCK_GPIO_INDEX],
        SuotaProfile.Constants.IMAGE_BANK_OLDEST
      )
      connect()
      Handler(mainLooper).postDelayed({
        startUpdate()
      }, 5000)
    }
  }

  private val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
  private val packetAdapter = object : SimpleAdapter<TitlePacketEntity, LayoutItemPacketBinding>(
    data = packetList,
    inflater = LayoutItemPacketBinding::inflate,
  ) {
    override fun onBindData(
      binding: LayoutItemPacketBinding?,
      t: TitlePacketEntity,
      position: Int
    ) {
      binding?.apply {
        if (t.json.isNotEmpty()) {
          tvWhich.visibility = View.GONE
          tvPacket.text = t.json
          tvPacket.setTextColor(
            ContextCompat.getColor(
              this@FunctionActivity,
              R.color.holo_purple
            )
          )
        } else {
          if (t.isApp) {
            tvWhich.setTextColor(
              ContextCompat.getColor(
                this@FunctionActivity,
                R.color.holo_blue_light
              )
            )
            tvPacket.setTextColor(
              ContextCompat.getColor(
                this@FunctionActivity,
                R.color.holo_blue_light
              )
            )
          } else {
            tvWhich.setTextColor(
              ContextCompat.getColor(
                this@FunctionActivity,
                R.color.holo_green_light
              )
            )
            tvPacket.setTextColor(
              ContextCompat.getColor(
                this@FunctionActivity,
                R.color.holo_green_light
              )
            )
          }
          val date = Date(t.time)
          val formatTime = formatter.format(date)
          tvWhich.text = "${t.title} ($formatTime)"
          tvWhich.visibility = View.VISIBLE
          tvPacket.text = ByteHexUtils.instance.bytesToHexString(t.packet)
        }
      }
    }

  }

//  inner class MySuotaCallback
}